library(palmerpenguins)
library(ggplot2)
library(dplyr)ggplot2RAdelaide 2025
July 8, 2025
R comes with some very powerful plotting capabilities
graphicsggplot2 changed everythingIntroVisualisation.Rcars dataset
speed (mph)dist (ft) each car takes to stopboxplot() can also create simple figures easilyy ~ x \(\implies\) y depends on xpairs()ggplot2ggplot2 has become the industry standard for visualisation (Wickham 2016)tidyverseTaken from https://r.qcbs.ca/workshop03/book-en/grammar-of-graphics-gg-basics.html
Everything is added in layers
tibble)x & y co-ordinatescolour, fill, shape, size, linetypealpha)carsspeed (mph)distance each car takes to stopx vs y plot using pointsspeeddistancex & ygeom_point() after calling ggplot()+ after ggplot() says “But wait! There’s more…”ggplot2 neither pipe had been developed yetgeom_point() after calling ggplot()
+ after ggplot() says “But wait! There’s more…”stat_smooth()
What visualisations could we produce to inspect penguins?
se = FALSE and see what happensggplot() \(\implies\) all layers will use thiscolour = species to geom_point() \(\implies\) ???~ notation to say all facets depend on speciesggplot2 will detect the most appropriate scale
scale_x_continuous() and scale_y_continuous()scale_x_log10(), scale_x_sqrt(), scale_x_reverse()yscale_colour_discrete() (Meh…)scale_colour_brewer(), scale_colour_viridis_d()scale_colour_brewer() \(\implies\) RColorBrewer::display.brewer.all()scale_colour_viridis_d() will give a colourblind-friendly palette
ggthemes (Wong 2011)
sex will have missing values## Try setting different point shapes based on the recorded sex
penguins |>
filter(!is.na(sex)) |> # Remove the penguins with unrecorded sex
ggplot(aes(x = bill_depth_mm, y = bill_length_mm, colour = species)) +
geom_point(aes(shape = sex)) + # Now we have a layer-specific aesthetic
stat_smooth(method = "lm", se = FALSE) +
scale_colour_colorblind()## Try setting different point shapes based on the recorded sex
penguins |>
filter(!is.na(sex)) |> # Remove the penguins with unrecorded sex
ggplot(aes(x = bill_depth_mm, y = bill_length_mm, colour = species)) +
geom_point(aes(shape = sex), size = 3) + # Change the point size
stat_smooth(method = "lm", se = FALSE) +
scale_colour_colorblind()scale_shape_manual()
scale_colour_manual()## Try setting different point shapes based on the recorded sex
penguins |>
filter(!is.na(sex)) |> # Remove the penguins with unrecorded sex
ggplot(aes(x = bill_depth_mm, y = bill_length_mm, colour = species)) +
geom_point(aes(shape = sex), size = 3) +
stat_smooth(method = "lm", se = FALSE) +
scale_colour_colorblind() +
scale_shape_manual(values = c(19, 1)) ## Manually choose the point shapes?pch and scroll down a little
## Try setting different point shapes based on the recorded sex
penguins |>
filter(!is.na(sex)) |> # Remove the penguins with unrecorded sex
ggplot(aes(x = bill_depth_mm, y = bill_length_mm, colour = species)) +
geom_point(aes(shape = sex), size = 3) +
stat_smooth(method = "lm", se = FALSE) +
scale_colour_colorblind() +
scale_shape_manual(values = c(19, 1)) +
labs(
# Manually add labels
x = "Bill Depth (mm)", y = "Bill Length (mm)",
colour = "Species", shape = "Sex"
) p
## Save the figure for exploring theme attributes
p <- penguins |>
filter(!is.na(sex)) |> # Remove the penguins with unrecorded sex
ggplot(aes(x = bill_depth_mm, y = bill_length_mm, colour = species)) +
geom_point(aes(shape = sex), size = 3) +
stat_smooth(method = "lm", se = FALSE) +
scale_colour_colorblind() +
scale_shape_manual(values = c(19, 1)) +
labs(
x = "Bill Depth (mm)", y = "Bill Length (mm)",
colour = "Species", shape = "Sex"
) theme_grey()theme_bw()
legend.position = "inside"element_text()?theme \(\implies\) 4 main types of ‘element’element_text()
element_line()
element_rect()
element_blank()
# Make the most horrible figure possible
p + theme_bw() +
theme(
## A slightly exaggerated modification of axis titles
axis.title = element_text(colour = "darkred", size = 16, face = "bold"),
## Make axes thick, blue lines. Ewww
axis.line = element_line(colour = "darkblue", linewidth = 2),
## Hide the underlying grid
panel.grid = element_blank(),
## Make the area background a light grey
plot.background = element_rect(fill = "grey70")
)geom_bar() & geom_col()geom_errorbar() & geom_errorbarh()geom_boxplot() & geom_violin()geom_density() & geom_histogram()geom_line(), geom_segment()geom_abline(), geom_hline() & geom_vline()geom_raster(), geom_tile() & geom_rect()sex as the predictorbody_mass_g may be a response variablecolour is generally applied to shape outlinesggplot2 will always separate multiple values/categoryfacet_wrap()facet_grid()) will allow for unequal-sized facetsgeom_jitter() will draw points but with noise in either directionalpha parameter will make the points partially transparenttrim = FALSE)ggplot2 is a bit uglyfill = "grey70" and colour = "black"binwidth is automatically set \(implies\) try binwidth = 100penguins |>
filter(!is.na(sex)) |>
summarise(
weight_mn = mean(body_mass_g, na.rm = TRUE),
weight_sd = sd(body_mass_g, na.rm = TRUE),
.by = c(species, sex)
) # A tibble: 6 × 4
species sex weight_mn weight_sd
<fct> <fct> <dbl> <dbl>
1 Adelie male 4043. 347.
2 Adelie female 3369. 269.
3 Gentoo female 4680. 282.
4 Gentoo male 5485. 313.
5 Chinstrap female 3527. 285.
6 Chinstrap male 3939. 362.
geom_col()## Begin creating a bar plot, with separate panels for each species
penguins |>
filter(!is.na(sex)) |>
summarise(
weight_mn = mean(body_mass_g, na.rm = TRUE),
weight_sd = sd(body_mass_g, na.rm = TRUE),
.by = c(species, sex)
) |>
ggplot(aes(sex, weight_mn, fill = sex)) +
geom_col() +
facet_wrap(~species, nrow = 1) penguins |>
filter(!is.na(sex)) |>
summarise(
weight_mn = mean(body_mass_g, na.rm = TRUE),
weight_sd = sd(body_mass_g, na.rm = TRUE),
.by = c(species, sex)
) |>
ggplot(aes(sex, weight_mn, fill = sex)) +
geom_col() +
## Now add errorbars adding/subtracting from the mean 'on the fly'
geom_errorbar(
aes(ymin = weight_mn - weight_sd, ymax = weight_mn + weight_sd),
width = 0.2 # Set the width of tails on the error bars
) +
facet_wrap(~species, nrow = 1) +
## Some extra code to make the plot look great
scale_y_continuous(expand = expansion(c(0, 0.05))) +
scale_fill_brewer(palette = "Set1") +
theme_bw()geom_text() will overlay labels exactly on the pointsgeom_text_repel() will shift labels marginally away from the pointsgeom_label() and geom_label_repel() will add borders and fill to labelsExport in the Plots paneA fabulous resource: https://r-graphics.org/
stat_ellipse() to your plot